package com.gupao.javavip.dubbo.rpc.serialize.messagepack;

import lombok.extern.apachecommons.CommonsLog;
import org.apache.dubbo.common.serialize.ObjectOutput;
import org.msgpack.MessagePack;

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;

/**
 * Messagepack object output implementation
 */
@CommonsLog
public class MessagepackObjectOutput implements ObjectOutput {
    private static final String NULL_DATA = "N";
    private static final byte[] NULL_DATA_TYPE = String.class.getName().getBytes();

    private final MessagePack messagePack;
    private final DataOutputStream dos;

    public MessagepackObjectOutput(OutputStream outputStream) {
        this.messagePack = new MessagePack();
        this.dos = new DataOutputStream(outputStream);
    }

    @SuppressWarnings("unchecked")
    @Override
    public void writeObject(Object obj) throws IOException {
        byte[] bytes = null;
        byte[] classNameBytes = null;

        if (obj == null) {
            classNameBytes = NULL_DATA_TYPE;
            bytes = messagePack.write(NULL_DATA);
        } else {
            // TODO HashMap类型需要做特殊处理，待优化
            classNameBytes = obj.getClass().getName().getBytes();
            bytes = messagePack.write(obj);
        }

        if (log.isDebugEnabled()) {
//            log.debug("messagePack encode...");
//            log.debug("className:" + new String(classNameBytes) + ",   classNameBytes.length:" + classNameBytes.length);
//            log.debug("bytes.length:" + bytes.length);
        }

        dos.writeInt(classNameBytes.length);
        dos.writeInt(bytes.length);
        dos.write(classNameBytes);
        dos.write(bytes);
    }

    @Override
    public void writeBool(boolean v) throws IOException {
        dos.writeBoolean(v);
    }

    @Override
    public void writeByte(byte v) throws IOException {
        dos.writeByte(v);
    }

    @Override
    public void writeShort(short v) throws IOException {
        dos.writeShort(v);
    }

    @Override
    public void writeInt(int v) throws IOException {
        dos.writeInt(v);
    }

    @Override
    public void writeLong(long v) throws IOException {
        dos.writeLong(v);
    }

    @Override
    public void writeFloat(float v) throws IOException {
        dos.writeFloat(v);
    }

    @Override
    public void writeDouble(double v) throws IOException {
        dos.writeDouble(v);
    }

    @Override
    public void writeUTF(String v) throws IOException {
        byte[] bytes = v.getBytes();
        dos.writeInt(bytes.length);
        dos.write(bytes);
    }

    @Override
    public void writeBytes(byte[] v) throws IOException {
        dos.writeInt(v.length);
        dos.write(v);
    }

    @Override
    public void writeBytes(byte[] v, int off, int len) throws IOException {
        dos.writeInt(len);
        byte[] bytes = new byte[len];
        System.arraycopy(v, off, bytes, 0, len);
        dos.write(bytes);
    }

    @Override
    public void flushBuffer() throws IOException {
        dos.flush();
    }
}
